import georegression.struct.point.Point2D_I32;

import java.awt.Dimension;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import java.util.List;

import boofcv.alg.enhance.EnhanceImageOps;
import boofcv.alg.feature.detect.edge.CannyEdge;
import boofcv.alg.filter.binary.BinaryImageOps;
import boofcv.alg.filter.binary.Contour;
import boofcv.alg.misc.ImageStatistics;
import boofcv.core.image.ConvertBufferedImage;
import boofcv.factory.feature.detect.edge.FactoryEdgeDetectors;
import boofcv.gui.ListDisplayPanel;
import boofcv.gui.image.ShowImages;
import boofcv.io.image.UtilImageIO;
import boofcv.struct.image.ImageSInt16;
import boofcv.struct.image.ImageUInt8;

import com.github.sarxos.webcam.Webcam;


public class Enhancement extends Thread {
	Webcam webcam;
	GestureRecognition gr;

	public Enhancement(Webcam webcam, GestureRecognition gr) {
		this.webcam = webcam;
		this.gr = gr;
	}

	public void run(){
		while(!gr.isEnd()){
			BufferedImage image = webcam.getImage();

			ImageUInt8 gray = ConvertBufferedImage.convertFrom(image,(ImageUInt8)null);
			ImageUInt8 adjusted = new ImageUInt8(gray.width, gray.height);
			
			CannyEdge<ImageUInt8,ImageSInt16> canny = FactoryEdgeDetectors.canny(2,true, true, ImageUInt8.class, ImageSInt16.class);
			ImageUInt8 edge0 = new ImageUInt8(gray.width,gray.height);
			ImageUInt8 edge1 = new ImageUInt8(gray.width,gray.height);
			ImageUInt8 edge2 = new ImageUInt8(gray.width,gray.height);
			canny.process(gray,0.1f,0.3f,edge0);
			

			int histogram[] = new int[256];
			int transform[] = new int[256];

			//ListDisplayPanel panel = new ListDisplayPanel();

			ImageStatistics.histogram(gray,histogram);
			EnhanceImageOps.equalize(histogram, transform);
			EnhanceImageOps.applyTransform(gray, transform, adjusted);
			//panel.addImage(ConvertBufferedImage.convertTo(adjusted,null),"Global");
			gr.getGraphics().drawImage(image, image.getWidth()*0, 0, gr);
			canny.process(adjusted,0.1f,0.3f,edge1);
			gr.getGraphics().drawImage(ConvertBufferedImage.convertTo(adjusted,null), image.getWidth()*1, 0, gr);
			//gr.getGraphics().drawimage
			
			EnhanceImageOps.equalizeLocal(gray, 50, adjusted, histogram, transform);
			//panel.addImage(ConvertBufferedImage.convertTo(adjusted,null),"Local");

			//panel.addImage(ConvertBufferedImage.convertTo(gray,null),"Original");

			//panel.setPreferredSize(new Dimension(gray.width,gray.height));
			//ShowImages.showWindow(panel,"Histogram");
			canny.process(adjusted,0.1f,0.3f,edge2);
			gr.getGraphics().drawImage(ConvertBufferedImage.convertTo(adjusted,null), image.getWidth()*2, 0, gr);
			
			List<Contour> contours0 = BinaryImageOps.contour(edge0, 8, null);
			List<Contour> contours1 = BinaryImageOps.contour(edge1, 8, null);
			List<Contour> contours2 = BinaryImageOps.contour(edge2, 8, null);
			
			BufferedImage imgEdge0 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
			for(Contour contour : contours0){
				List<Point2D_I32> points = contour.external;
				Polygon poly = new Polygon();
				for(Point2D_I32 p : points){
					poly.addPoint(p.x, p.y);
				}
				imgEdge0.getGraphics().drawPolygon(poly);
			}
			gr.getGraphics().drawImage(imgEdge0, image.getWidth()*0, image.getHeight()*1, gr);
			//---1
			BufferedImage imgEdge1 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
			for(Contour contour : contours1){
				List<Point2D_I32> points = contour.external;
				Polygon poly = new Polygon();
				for(Point2D_I32 p : points){
					poly.addPoint(p.x, p.y);
				}
				imgEdge1.getGraphics().drawPolygon(poly);
			}
			gr.getGraphics().drawImage(imgEdge1, image.getWidth()*1, image.getHeight()*1, gr);
			//---2
			BufferedImage imgEdge2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
			for(Contour contour : contours0){
				List<Point2D_I32> points = contour.external;
				Polygon poly = new Polygon();
				for(Point2D_I32 p : points){
					poly.addPoint(p.x, p.y);
				}
				imgEdge2.getGraphics().drawPolygon(poly);
			}
			gr.getGraphics().drawImage(imgEdge2, image.getWidth()*2, image.getHeight()*1, gr);
		}
	}
	
	/**
	 * When an image is sharpened the intensity of edges are made more extreme while flat regions remain unchanged.
	 */
	public static void sharpen() {
//		BufferedImage buffered = UtilImageIO.loadImage("../data/applet/enhance/dull.jpg");
		BufferedImage buffered = UtilImageIO.loadImage("../data/applet/enhance/dark.jpg");
		ImageUInt8 gray = ConvertBufferedImage.convertFrom(buffered,(ImageUInt8)null);
		ImageUInt8 adjusted = new ImageUInt8(gray.width, gray.height);


		ListDisplayPanel panel = new ListDisplayPanel();

		EnhanceImageOps.sharpen4(gray, adjusted);
		panel.addImage(ConvertBufferedImage.convertTo(adjusted,null),"Sharpen-4");

		EnhanceImageOps.sharpen8(gray, adjusted);
		panel.addImage(ConvertBufferedImage.convertTo(adjusted,null),"Sharpen-8");

		panel.addImage(ConvertBufferedImage.convertTo(gray,null),"Original");

		panel.setPreferredSize(new Dimension(gray.width,gray.height));
		ShowImages.showWindow(panel,"Sharpen");
	}
}
